﻿/* 2014/1/5 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Cosmos.Collections.Generic;
using Cosmos.IO.FileSystemOperation;
using Cosmos.IO.FileSystemPath;
using Cosmos.Security.Cryptography;
using Cosmos.Shortcuts;
using Cosmos.Windows.Forms.FileList;

namespace PictureManager
{
    public partial class CompareFileForm : Form
    {
        private enum OperationType
        {
            None,
            Rename,
            Move,
            Copy,
            Delete,
        }

        private const string _sourceFileNameTag = "<s>";
        private const string _targetFileNameTag = "<t>";

        private const string _noneOperationCHS = "无操作";
        private const string _renameOperationCHS = "重命名";
        private const string _moveOperationCHS = "移动到";
        private const string _copyOperationCHS = "复制到";
        private const string _deleteOperationCHS = "删除";

        private const string _noneParameterCHS = "无参数";
        private const string _renameParameterCHS = "重命名方式";
        private const string _moveParameterCHS = "移动到";
        private const string _copyParameterCHS = "复制到";

        private static ShortcutOperationInformation[] _validSourceOperations = new ShortcutOperationInformation[] { 
            new ShortcutOperationInformation((int)OperationType.None, _noneOperationCHS, 0, _noneParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Rename, _renameOperationCHS, 1, _renameParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Move, _moveOperationCHS, 1, _moveParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Copy, _copyOperationCHS, 1, _copyParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Delete, _deleteOperationCHS, 0, _noneParameterCHS)};

        private static ShortcutOperationInformation[] _validTargetOperations = new ShortcutOperationInformation[] { 
            new ShortcutOperationInformation((int)OperationType.None, _noneOperationCHS, 0, _noneParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Rename, _renameOperationCHS, 1, _renameParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Move, _moveOperationCHS, 1, _moveParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Copy, _copyOperationCHS, 1, _copyParameterCHS),
            new ShortcutOperationInformation((int)OperationType.Delete, _deleteOperationCHS, 0, _noneParameterCHS)};

        private FileListSupervisor _sourceFileListSupervisor;
        private FileListSupervisor _targetFileListSupervisor;

        private OperationType _sourceOperation;
        private OperationType _targetOperation;
        private string _sourceParameter;
        private string _targetParameter;

        /*private string _deletedFilePath;
        private string _renamedOldFilePath;
        private string _renamedNewFilePath;
        private string _createdFilePath;*/

        private DictionaryDuplicateList<HashValue, string> _duplicateSourcePaths;

        public CompareFileForm()
        {
            InitializeComponent();

            foreach (ShortcutOperationInformation anOperation in _validSourceOperations)
            {
                sourceOperationToolStripComboBox.Items.Add(new ComboBoxItem(anOperation.OperationDescription, anOperation));
            }

            foreach(ShortcutOperationInformation anOperation in _validTargetOperations)
            {
                targetOperationToolStripComboBox.Items.Add(new ComboBoxItem(anOperation.OperationDescription, anOperation));
            }
            sourceOperationToolStripComboBox.SelectedIndex = 0;
            targetOperationToolStripComboBox.SelectedIndex = 0;
            
            _sourceFileListSupervisor = new FileListSupervisor();
            _sourceFileListSupervisor.Register(sourceListView);
            _targetFileListSupervisor = new FileListSupervisor();
            _targetFileListSupervisor.Register(targetListView);

            _duplicateSourcePaths = new DictionaryDuplicateList<HashValue, string>();
        }

        public void ClearSource()
        {
            _sourceFileListSupervisor.Clear();
        }

        public void ClearTarget()
        {
            _targetFileListSupervisor.Clear();
        }

        public void AddSource(IEnumerable<string> paths)
        {
            _sourceFileListSupervisor.AddRange(paths);
            sourceListView.HashAllFile();
        }

        public void AddTarget(IEnumerable<string> paths)
        {
            _targetFileListSupervisor.AddRange(paths);
            targetListView.HashAllFile();
        }

        public void RemoveSource(IEnumerable<string> paths)
        {
            foreach(string aPath in paths)
            {
                _sourceFileListSupervisor.Remove(aPath);
            }
        }

        public void RemoveTarget(IEnumerable<string> paths)
        {
            foreach (string aPath in paths)
            {
                _targetFileListSupervisor.Remove(aPath);
            }
        }

        private void VerifyFile()
        {
            bool isArgsReady = true;
            ComboBoxItem item = (ComboBoxItem)sourceOperationToolStripComboBox.SelectedItem;
            _sourceOperation = ((OperationType)((ShortcutOperationInformation)item.Value).Operation);
            _sourceParameter = sourceParameterToolStripTextBox.Text;
            switch (_sourceOperation)
            {
                case OperationType.None:
                    break;

                case OperationType.Rename:
                    string newFileName = _sourceParameter.Replace(_sourceFileNameTag, "");
                    if (!CheckFileName(newFileName))
                    {
                        MessageBox.Show("重命名包含无效字符", "源文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Move:
                    if (!Directory.Exists(_sourceParameter))
                    {
                        MessageBox.Show("指定的目录不存在", "源文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Copy:
                    if (!Directory.Exists(_sourceParameter))
                    {
                        MessageBox.Show("指定的目录不存在", "源文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Delete:
                    break;

                default:
                    break;
            }

            if (!isArgsReady)
                return;

            _duplicateSourcePaths.Clear();

            for (int i = 0; i < _sourceFileListSupervisor.Count; i++)
            {
                string filePath = _sourceFileListSupervisor[i];
                HashValue fileHash = sourceListView.GetHash(filePath);

                string[] duplicatePaths;
                if (_duplicateSourcePaths.TryGetValues(fileHash, out duplicatePaths))
                {
                    OperateSourceFile(filePath, duplicatePaths, fileHash);
                }

                _duplicateSourcePaths.Add(fileHash, filePath);
            }

            sourceListView.Refresh();
        }

        private void CompareFile()
        {
            bool isArgsReady = true;
            ComboBoxItem item = (ComboBoxItem)targetOperationToolStripComboBox.SelectedItem;
            _targetOperation = ((OperationType)((ShortcutOperationInformation)item.Value).Operation);
            _targetParameter = targetParameterToolStripTextBox.Text;
            switch (_targetOperation)
            {
                case OperationType.None:
                    break;

                case OperationType.Rename:
                    string newFileName = _targetParameter.Replace(_sourceFileNameTag, "")
                                            .Replace(_targetFileNameTag, "");
                    if (!CheckFileName(newFileName))
                    {
                        MessageBox.Show("重命名包含无效字符", "目标文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Move:
                    if (!Directory.Exists(_targetParameter))
                    {
                        MessageBox.Show("指定的目录不存在", "目标文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Copy:
                    if (!Directory.Exists(_targetParameter))
                    {
                        MessageBox.Show("指定的目录不存在", "目标文件操作参数错误");
                        isArgsReady = false;
                    }
                    break;

                case OperationType.Delete:
                    break;

                default:
                    break;
            }

            if (!isArgsReady)
                return;

            for (int i = 0; i < _targetFileListSupervisor.Count; i++)
            {
                string targetPath = _targetFileListSupervisor[i];
                HashValue fileHash = targetListView.GetHash(targetPath);

                string[] sourcePaths;
                if (_duplicateSourcePaths.TryGetValues(fileHash, out sourcePaths))
                {
                    OperationTargetFile(targetPath, sourcePaths);
                }
            }
        }

        private void OperateSourceFile(string filePath, string[] duplicatedPaths, HashValue fileHash)
        {
            Color itemForeColor = Color.FromArgb(fileHash.GetHashCode());
            Color itemBackColor = Color.FromArgb(0xFFFFFF ^ fileHash.GetHashCode());

            sourceListView.SetBackColor(filePath, itemBackColor);
            sourceListView.SetForeColor(filePath, itemForeColor);
            if (duplicatedPaths.Length == 1)
            {
                sourceListView.SetBackColor(duplicatedPaths[0], itemBackColor);
                sourceListView.SetForeColor(duplicatedPaths[0], itemForeColor);
            }

            FileOperationRecord operationRecord = null;
            switch (_sourceOperation)
            {
                case OperationType.None:
                    break;

                case OperationType.Rename:
                    string oldFileName = Path.GetFileName(filePath);
                    string newFileName = _sourceParameter;
                    newFileName = newFileName.Replace(_sourceFileNameTag, oldFileName);
                    operationRecord = RenameFile(filePath, newFileName);
                    break;

                case OperationType.Move:
                    operationRecord = MoveFile(filePath, _sourceParameter);
                    break;

                case OperationType.Copy:
                    operationRecord = CopyFile(filePath, _sourceParameter);
                    break;

                case OperationType.Delete:
                    operationRecord = DeleteFile(filePath);
                    break;

                default:
                    break;
            }

            if (operationRecord != null)
            {
                switch (operationRecord.Type)
                {
                    case FileOperationType.None:
                        break;

                    case FileOperationType.Move:
                        _sourceFileListSupervisor.Rename(operationRecord.SourcePath, operationRecord.TargetPath);
                        break;

                    case FileOperationType.Copy:
                        break;

                    case FileOperationType.Delete:
                        _sourceFileListSupervisor.Remove(operationRecord.SourcePath);
                        break;

                    default:
                        break;
                }
            }
        }

        private void OperationTargetFile(string targetPath, string[] sourcePaths)
        {
            FileOperationRecord operationRecord = null;
            switch (_sourceOperation)
            {
                case OperationType.None:
                    break;

                case OperationType.Rename:
                    string oldFileName = Path.GetFileName(targetPath);
                    string newFileName = _targetParameter;
                    string sourceFileName = Path.GetFileName(sourcePaths[0]);
                    newFileName = newFileName.Replace(_targetFileNameTag, oldFileName)
                                    .Replace(_sourceFileNameTag, sourceFileName);
                    operationRecord = RenameFile(targetPath, newFileName);
                    break;

                case OperationType.Move:
                    operationRecord = MoveFile(targetPath, _targetParameter);
                    break;

                case OperationType.Copy:
                    operationRecord = CopyFile(targetPath, _targetParameter);
                    break;

                case OperationType.Delete:
                    operationRecord = DeleteFile(targetPath);
                    break;

                default:
                    break;
            }

            if (operationRecord != null)
            {
                switch (operationRecord.Type)
                {
                    case FileOperationType.None:
                        break;

                    case FileOperationType.Move:
                        _targetFileListSupervisor.Rename(operationRecord.SourcePath, operationRecord.TargetPath);
                        break;

                    case FileOperationType.Copy:
                        break;

                    case FileOperationType.Delete:
                        _targetFileListSupervisor.Remove(operationRecord.SourcePath);
                        break;

                    default:
                        break;
                }
            }
        }

        private bool CheckFileName(string fileName)
        {
            foreach (char aChar in FilePath.GetInvalidFileNameChars())
            {
                if(fileName.Contains(aChar))
                    return false;
            }
            return true;
        }

        private FileOperationRecord RenameFile(string filePath, string newFileName)
        {
            string dirPath = Path.GetDirectoryName(filePath);
            string newFilePath = Path.Combine(dirPath, newFileName);

            if (filePath.Equals(newFilePath))
                return null;

            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在：" + filePath, "操作失败");
                return null;
            }

            if (File.Exists(newFilePath))
            {
                MessageBox.Show("文件名已存在：" + newFilePath, "操作失败");
                return null;
            }

            FileOperationRecord operationRecord = null;
            try
            {
                File.Move(filePath, newFilePath);
                operationRecord = FileOperationRecord.CreateMoveRecord(filePath, newFilePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return operationRecord;


            /*string dirPath = Path.GetDirectoryName(filePath);
            string newFilePath = Path.Combine(dirPath, newFileName);

            _renamedOldFilePath = null;
            _renamedNewFilePath = null;
            sourceFileSystemWatcher.Path = dirPath;
            sourceFileSystemWatcher.EnableRaisingEvents = true;
            ApiFileOperation.RenameFile(filePath, newFilePath);
            sourceFileSystemWatcher.EnableRaisingEvents = false;

            if (_renamedOldFilePath != null && _renamedNewFilePath != null)
                return FileOperationRecord.CreateMoveRecord(_renamedOldFilePath, _renamedNewFilePath);
            else
                return null;*/
        }

        private FileOperationRecord MoveFile(string filePath, string dirPath)
        {
            string fileName = Path.GetFileName(filePath);
            string newFilePath = Path.Combine(dirPath, fileName);  
          
            if (filePath.Equals(newFilePath))
                return null;

            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在：" + filePath, "操作失败");
                return null;
            }

            if (!Directory.Exists(dirPath))
            {
                MessageBox.Show("目录不存在：" + dirPath, "操作失败");
                return null;
            }

            if (File.Exists(newFilePath))
            {
                MessageBox.Show("文件名已存在：" + newFilePath, "操作失败");
                return null;
            }
            FileOperationRecord operationRecord = null;
            try
            {
                File.Move(filePath, newFilePath);
                operationRecord = FileOperationRecord.CreateMoveRecord(filePath, newFilePath);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return operationRecord;

            /*string oldDirPath = Path.GetDirectoryName(filePath);
            string fileName = Path.GetFileName(filePath);

            _deletedFilePath = null;
            _createdFilePath = null;
            sourceFileSystemWatcher.Path = oldDirPath;
            sourceFileSystemWatcher.EnableRaisingEvents = true;
            targetFileSystemWatcher.Path = dirPath;
            targetFileSystemWatcher.EnableRaisingEvents = true;
            ApiFileOperation.MoveFile(filePath, dirPath);
            targetFileSystemWatcher.EnableRaisingEvents = false;
            sourceFileSystemWatcher.EnableRaisingEvents = false;

            if (_deletedFilePath != null && _createdFilePath != null)
                return FileOperationRecord.CreateMoveRecord(filePath, _createdFilePath);
            else
                return null;*/
        }

        private FileOperationRecord CopyFile(string filePath, string dirPath)
        {
            string fileName = Path.GetFileName(filePath);
            string newFilePath = Path.Combine(dirPath, fileName);

            if (filePath.Equals(newFilePath))
                return null;
            
            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在：" + filePath, "操作失败");
                return null;
            }

            if (!Directory.Exists(dirPath))
            {
                MessageBox.Show("目录不存在：" + dirPath, "操作失败");
                return null;
            }

            if (File.Exists(newFilePath))
            {
                MessageBox.Show("文件名已存在：" + newFilePath, "操作失败");
                return null;
            }

           FileOperationRecord operationRecord = null;
            try
            {
                File.Copy(filePath, newFilePath);
                operationRecord = FileOperationRecord.CreateCopyRecord(filePath, newFilePath);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return operationRecord;
            
            /*_createdFilePath = null;
            targetFileSystemWatcher.Path = dirPath;
            targetFileSystemWatcher.EnableRaisingEvents = true;
            ApiFileOperation.CopyFile(filePath, dirPath);
            targetFileSystemWatcher.EnableRaisingEvents = false;

            if (_createdFilePath != null)
                return FileOperationRecord.CreateCopyRecord(filePath, _createdFilePath);
            else
                return null;*/
        }

        private FileOperationRecord DeleteFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                MessageBox.Show("文件不存在：" + filePath, "操作失败");
                return null;
            }

            FileOperationRecord operationRecord = null;
            try
            {
                File.Delete(filePath);
                operationRecord = FileOperationRecord.CreateDeleteRecord(filePath);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return operationRecord;

            /*string dirPath = Path.GetDirectoryName(filePath);

            _deletedFilePath = null;
            sourceFileSystemWatcher.Path = dirPath;
            sourceFileSystemWatcher.EnableRaisingEvents = true;
            ApiFileOperation.DeleteFile(filePath);
            sourceFileSystemWatcher.EnableRaisingEvents = false;

            if (_deletedFilePath != null)
                return FileOperationRecord.CreateDeleteRecord(_deletedFilePath);
            else
                return null;*/
        }

        #region Event Handler Methods

        private void CompareFileForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            Hide();
        }

        private void sourceListView_HashCalculating(object sender, EventArgs e)
        {
            verifyToolStripButton.Enabled = false;
        }

        private void sourceListView_HashCalculated(object sender, EventArgs e)
        {
            if (!sourceListView.IsHashing && !targetListView.IsHashing)
                verifyToolStripButton.Enabled = true;
        }

        private void targetListView_HashCalculating(object sender, EventArgs e)
        {
            verifyToolStripButton.Enabled = false;
        }

        private void targetListView_HashCalculated(object sender, EventArgs e)
        {
            if (!sourceListView.IsHashing && !targetListView.IsHashing)
                verifyToolStripButton.Enabled = true;
        }

        private void sourceOperationToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBoxItem selectedItem = (ComboBoxItem)sourceOperationToolStripComboBox.SelectedItem;
            ShortcutOperationInformation operation = (ShortcutOperationInformation)selectedItem.Value;
            if (operation.ParamterCount == 0)
            {
                sourceParameterToolStripTextBox.Visible = false;
            }
            else
            {
                sourceParameterToolStripTextBox.Visible = true;
            }
        }

        private void targetOperationToolStripComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBoxItem selectedItem = (ComboBoxItem)targetOperationToolStripComboBox.SelectedItem;
            ShortcutOperationInformation operation = (ShortcutOperationInformation)selectedItem.Value;
            if (operation.ParamterCount == 0)
            {
                targetParameterToolStripTextBox.Visible = false;
            }
            else
            {
                targetParameterToolStripTextBox.Visible = true;
            }
        }

        private void verifyToolStripButton_Click(object sender, EventArgs e)
        {
            VerifyFile();
        }

        private void compareToolStripButton_Click(object sender, EventArgs e)
        {
            CompareFile();
        }

        private void clearSourceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClearSource();
        }

        private void removeSourceToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string[] paths = sourceListView.SelectedPaths;
            RemoveSource(paths);
        }

        private void clearTargetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClearTarget();
        }

        private void removeTargetToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string[] paths = targetListView.SelectedPaths;
            RemoveTarget(paths);
        }

        #endregion
    }
}
